/*
* $Id: QueenBeeManager.cpp 154 2010-09-27 08:10:48Z volok-aleksej@yandex.ru $
*
* Copyright 2010 by Volokitin Alexey
* All rights reserved
*
*/
#include "Common/include.h"
#include "JournalInterface.h"
#include "QueenBeeManager.h"
#include "Database/Tables/QueenBeeTable.h"
#include "Database/Operation/ChangeQBParamOperation.h"
#include "Database/Operation/DeleteQBFamilyOperation.h"
#include "Event/EventId.h"

#include "Common/RefObject.h"
CRefObject<CQueenBeeManager> g_QueenBeeManager;
CQueenBeeManager* IJournalComponent::GetQueenBeeManager(){
	return g_QueenBeeManager.GetObject();
}

CQueenBeeManager::CQueenBeeManager(){}
CQueenBeeManager::~CQueenBeeManager(){}

void CQueenBeeManager::Init(){
	m_aQueenBee.clear();
	m_aFamilyQB.clear();
	m_aChildQB.clear();
	m_aFilter.clear();
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CQueenBeeTable qBee;
	IResult* pResult = qBee.GetValue(pDb);
	for(int i = 0; i < (int)pResult->GetSizeResult(); i++){
		CQueenBeeTable::content* pContent = (CQueenBeeTable::content*)(*pResult)[i];
		queen_bee qb;
		qb.s_strName = pContent->s_strName;
		qb.s_strDescription = pContent->s_strDescription;
		qb.s_strFert = pContent->s_strFert;
		qb.s_nIdParentQueenBee = pContent->s_nIdParentQueenBee;
		qb.s_nIdFamily = pContent->s_nIdFamily;
		qb.s_date = pContent->s_date;
		qb.s_bDead = pContent->s_bDead;
		qb.s_nBreed = pContent->s_breed;
		m_aQueenBee.insert(std::make_pair(pContent->s_nId, qb));
		m_aFamilyQB[qb.s_nIdFamily].push_back(pContent->s_nId);
		m_aFilter[qb.s_strName[0]].push_back(pContent->s_nId);
		if(qb.s_nIdParentQueenBee)
			m_aChildQB[qb.s_nIdParentQueenBee].push_back(pContent->s_nId);
	}
	pResult->Free();
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
}

int CQueenBeeManager::AddQueenBee(const std::tstring& strName, const std::tstring strDescription,
								  const std::tstring& strFert, time_t date, bool bDead, QueenBee::breed nBread, int nIdFamily){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	queen_bee qb;
	CQueenBeeTable table;
	table.m_content.s_strName = qb.s_strName = strName;
	table.m_content.s_nIdFamily = qb.s_nIdFamily = nIdFamily;
	table.m_content.s_strDescription = qb.s_strDescription = strDescription;
	table.m_content.s_strFert = qb.s_strFert = strFert;
	table.m_content.s_date = qb.s_date = date;
	table.m_content.s_bDead = qb.s_bDead = bDead;
	table.m_content.s_breed = qb.s_nBreed = nBread;
	table.SetValue(pDb);
	std::map<int, queen_bee>::iterator it = m_aQueenBee.insert(m_aQueenBee.begin(), std::make_pair(table.m_content.s_nId, qb));
	m_aFamilyQB[nIdFamily].push_back(table.m_content.s_nId);
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	IEventManager::GetEventManager()->SendEvent(QUEEN_BEE_DB_CHANGE_EVENT);
	return it->first;
}

void CQueenBeeManager::DeleteQueenBee(int nId){
	IDatabase* pDatabase = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDatabase->BeginTransaction(_T("Delete Queen Bee"));
	CQueenBeeTable table;
	table.m_content.s_nId = nId;
	table.DeleteValue(pDatabase);
	pDatabase->EndTransaction(_T("Delete Queen Bee"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDatabase);
	std::map<int, queen_bee>::iterator itMain = m_aQueenBee.find(nId);
	queen_bee qb;
	if(itMain != m_aQueenBee.end()){
		qb = itMain->second;
		m_aQueenBee.erase(itMain);
	}
	std::map<int, std::vector<int> >::iterator it = m_aChildQB.find(nId);
	if(it != m_aChildQB.end()){
		for(std::vector<int>::iterator it1 = it->second.begin(); it1 != it->second.end(); it1++)
			m_aQueenBee[*it1].s_nIdParentQueenBee = 0;
		m_aChildQB.erase(it);
	}
	it = m_aChildQB.find(qb.s_nIdParentQueenBee);
	if(it != m_aChildQB.end()){
		std::vector<int>::iterator it1 = std::find(it->second.begin(), it->second.end(), nId);
		if(it1 != it->second.end())
			it->second.erase(it1);
	}
	it = m_aFamilyQB.find(qb.s_nIdFamily);
	if(it != m_aFamilyQB.end()){
		std::vector<int>::iterator it1 = std::find(it->second.begin(), it->second.end(), nId);
		if(it1 != it->second.end())
			it->second.erase(it1);
	}
	IEventManager::GetEventManager()->SendEvent(QUEEN_BEE_DB_CHANGE_EVENT);
}

void CQueenBeeManager::ChangeQueenBee(int nId, const std::tstring& strName, const std::tstring strDescription,
									  const std::tstring& strFert, time_t date, bool bDead, QueenBee::breed nBread){
	if(strName[0] != m_aQueenBee[nId].s_strName[0]){
		TCHAR first = m_aQueenBee[nId].s_strName[0];
		std::vector<int>::iterator it = std::find(m_aFilter[first].begin(), m_aFilter[first].end(), nId);
		if(it != m_aFilter[first].end())
			m_aFilter[first].erase(it);
		if(m_aFilter[first].empty())
			m_aFilter.erase(first);
		m_aFilter[strName[0]].push_back(nId);
	}
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CQueenBeeTable table;
	table.m_content.s_nId = nId;
	table.m_content.s_strName = m_aQueenBee[nId].s_strName = strName;
	table.m_content.s_strDescription = m_aQueenBee[nId].s_strDescription = strDescription;
	table.m_content.s_strFert = m_aQueenBee[nId].s_strFert = strFert;
	table.m_content.s_date = m_aQueenBee[nId].s_date = date;
	table.m_content.s_bDead = m_aQueenBee[nId].s_bDead = bDead;
	table.m_content.s_breed = m_aQueenBee[nId].s_nBreed = nBread;
	table.UpdateValue(pDb);
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	IEventManager::GetEventManager()->SendEvent(QUEEN_BEE_DB_CHANGE_EVENT);
}

std::map<int, CQueenBeeManager::queen_bee> CQueenBeeManager::GetFamilyQB(int nIdFamily){
	std::map<int, queen_bee> aQueenBee;
	for(std::vector<int>::iterator it = m_aFamilyQB[nIdFamily].begin(); it != m_aFamilyQB[nIdFamily].end(); it++)
		aQueenBee.insert(std::make_pair(*it, m_aQueenBee[*it]));
	return aQueenBee;
}

CQueenBeeManager::queen_bee CQueenBeeManager::GetQueenBee(int nId){
	if(nId)
		return m_aQueenBee[nId];
	return CQueenBeeManager::queen_bee();
}

int CQueenBeeManager::FindQueenBee(const std::tstring& strName){
	if(strName.empty())
		return 0;
	std::map<TCHAR, std::vector<int> >::iterator it = m_aFilter.find(strName[0]);
	if(it != m_aFilter.end()){
		int pos = 1;
		std::vector<int>::iterator itPos = m_aFilter[strName[0]].begin();
		for(std::vector<int>::iterator it = m_aFilter[strName[0]].begin(); it != m_aFilter[strName[0]].end(); it++){
			std::tstring sName = m_aQueenBee[*it].s_strName;
			int i = 1;
			for(; i < (int)strName.size() && i < (int)sName.size(); i++){
				if(strName[i] != sName[i])
					break;
			}
			if(pos < i){
				pos = i;
				itPos = it;
			}
		}
		return *itPos;
	}
	return 0;
}

std::map<int, CQueenBeeManager::queen_bee> CQueenBeeManager::GetQueenBees(){
	return m_aQueenBee;
}

void CQueenBeeManager::ChangeParentQB(int nId, int nIdParent){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CChangeQBParamOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_type = QueenBee::PARENT;
	operation.m_content.s_nIdParent = nIdParent;
	operation.UpdateValue(pDb);
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	int nParentID = m_aQueenBee[nId].s_nIdParentQueenBee;
	for(std::vector<int>::iterator it = m_aChildQB[nParentID].begin(); nParentID && it != m_aChildQB[nParentID].end(); it++){
		if(*it == nId){
			m_aChildQB[nParentID].erase(it);
			break;
		}
	}
	if(nIdParent)
		m_aChildQB[nIdParent].push_back(nId);
	m_aQueenBee[nId].s_nIdParentQueenBee = nIdParent;
	IEventManager::GetEventManager()->SendEvent(QUEEN_BEE_DB_CHANGE_EVENT);
}

std::map<int, CQueenBeeManager::queen_bee> CQueenBeeManager::GetChildQB(int nId){
	std::map<int, CQueenBeeManager::queen_bee> aQb;
	for(std::vector<int>::iterator it = m_aChildQB[nId].begin(); it != m_aChildQB[nId].end(); it++)
		aQb.insert(std::make_pair(*it, m_aQueenBee[*it]));
	return aQb;
}

void CQueenBeeManager::ChangeFamilyQB(int nId, int nIdFamily){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CChangeQBParamOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_type = QueenBee::FAMILY;
	operation.m_content.s_nIdFamily = nIdFamily;
	operation.UpdateValue(pDb);
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	int nFamilyID = m_aQueenBee[nId].s_nIdFamily;
	for(std::vector<int>::iterator it = m_aFamilyQB[nFamilyID].begin(); nFamilyID && it != m_aFamilyQB[nFamilyID].end(); it++){
		if(*it == nId){
			m_aFamilyQB[nFamilyID].erase(it);
			break;
		}
	}
	if(nIdFamily)
		m_aFamilyQB[nIdFamily].push_back(nId);
	m_aQueenBee[nId].s_nIdFamily = nIdFamily;
	IEventManager::GetEventManager()->SendEvent(QUEEN_BEE_DB_CHANGE_EVENT);
}

void CQueenBeeManager::DeleteFamilyQB(int nId){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CDeleteQBFamilyOperation operation;
	operation.m_content.s_nId = nId;
	operation.DeleteValue(pDb);
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	m_aFamilyQB.erase(nId);
	IEventManager::GetEventManager()->SendEvent(QUEEN_BEE_DB_CHANGE_EVENT);
}
